package service.impl;
import service.PhoneBillBillingService;
import java.time.Duration;
import java.time.ZonedDateTime;

/**
 * 实现通话时长计费服务接口.
 *
 * @author zhiyong
 */
public class PhoneBillBillingServiceImpl implements PhoneBillBillingService {
    // 计费相关常量
    //通话时长计费阈值（分钟）.
    private static final long FREE_MINUTES_THRESHOLD = 20;
    //通话时长计费基础费率（每分钟0.05元）.
    private static final double BASE_RATE = 0.05;
    //通话时长计费基础费率（每分钟0.05元）.
    private static final double BASE_MONEY = 1.0;
    //通话时长计费额外费率（每分钟0.1元）.
    private static final double EXTRA_RATE = 0.1;
    //通话时长上限（小时）
    private static final long MAX_CALL_MINUTES = 30;
    // 1 分钟 = 60 秒
    private static final long SECONDS_PER_MINUTE = 60;
    //向上取整时的秒数
    private static final long ROUND_UP_SECONDS = 59;
    /**
     * 计算20分钟内的花费.
     * @param airTime 通话时长（分钟）
     * @return 通话花费金额
     */
    private Double calculateTheCostWithinThresholdMinutes(long airTime) {
        if (airTime > FREE_MINUTES_THRESHOLD) {
            return BASE_MONEY;
        } else {
            return airTime * BASE_RATE;
        }
    }

    /**
     * 计算超过二十分钟后的额外花费.
     * @param airTime 通话时长（分钟）
     * @return 额外花费金额
     */
    private Double calculateTheCostBeyondThresholdMinutes(long airTime) {
        long extraMinutes = airTime - FREE_MINUTES_THRESHOLD;
        if (extraMinutes <= 0) {
            return 0.0;
        }
        return extraMinutes * EXTRA_RATE;
    }

    /**
     * 毫秒数到分钟数，不满一分钟记为一分钟.
     * @param seconds 秒数
     * @return 分钟数
     */
    public Long calculateMinutes(Long seconds) {
        if (seconds < 0) {
            throw new IllegalArgumentException("秒数必须是一个非负的整数");
        }
        return (seconds + ROUND_UP_SECONDS) / SECONDS_PER_MINUTE;
    }

    /**
     * 计算通话时长.
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 通话时长（秒）
     */
    @Override
    public Long calculateAirtime(ZonedDateTime startTime, ZonedDateTime endTime) {
        return Duration.between(startTime, endTime).getSeconds();
    }

    /**
     * 计算花费.
     * @param airTime 通话时长（分钟）
     * @return 通话花费金额
     */
    @Override
    public Double calculateTheCost(Long airTime) {
        if (airTime > MAX_CALL_MINUTES * SECONDS_PER_MINUTE || airTime <= 0) {
            throw new IllegalArgumentException("通话时长不能超过30分钟且不能为零");
        }
        //计算二十分钟内的花费
        Double baseSpend = calculateTheCostWithinThresholdMinutes(airTime);

        //计算超过二十分钟的花费
        Double extraSpend = calculateTheCostBeyondThresholdMinutes(airTime);
        return baseSpend + extraSpend;
    }
    /**
     * 计算分钟数.
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 通话分钟数
     */
    @Override
    public Long calculateMinutes(ZonedDateTime startTime, ZonedDateTime endTime) {
        Long seconds = calculateAirtime(startTime, endTime);
        return calculateMinutes(seconds);
    }

    /**
     * 计算花费.
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 通话花费金额
     */
    @Override
    public Double calculateTheCost(ZonedDateTime startTime, ZonedDateTime endTime) {
        Long minutes = calculateMinutes(startTime, endTime);
        return calculateTheCost(minutes);
    }
}
